package _greedy

import org.junit.Assert
import org.junit.Test

/**
 * 贪心算法
 * https://leetcode.cn/problems/jump-game-ii/description
 *
 * 45. 跳跃游戏 II
 * 给定一个长度为 n 的 0 索引整数数组 nums。初始位置在下标 0。
 *
 * 每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说，如果你在索引 i 处，你可以跳转到任意 (i + j) 处：
 *
 * 0 <= j <= nums[i] 且
 * i + j < n
 * 返回到达 n - 1 的最小跳跃次数。测试用例保证可以到达 n - 1。
 *
 *
 * 示例 1:
 * 输入: nums = [2,3,1,1,4]
 * 输出: 2
 * 解释: 跳到最后一个位置的最小跳跃数是 2。
 *      从下标为 0 跳到下标为 1 的位置，跳 1 步，然后跳 3 步到达数组的最后一个位置。
 *
 * 示例 2:
 * 输入: nums = [2,3,0,1,4]
 * 输出: 2
 *
 *
 * 提示:
 *
 * 1 <= nums.length <= 104
 * 0 <= nums[i] <= 1000
 * 题目保证可以到达 n - 1
 */
class leetcode_45 {
    @Test
    fun test_1() {
        val actual = jump(intArrayOf(2, 3, 1, 1, 4))
        val expected = 2
        Assert.assertEquals(expected, actual)
    }

    @Test
    fun test_2() {
        val actual = jump(intArrayOf(2,3,0,1,4))
        val expected = 2
        Assert.assertEquals(expected, actual)
    }


    private fun jump(nums: IntArray): Int {
        if (nums.size == 1) {
            return 0
        }

        var currentIndex = 0 // 当前能够达到的最远索引
        var nextIndex = 0 // 下一次能够达到的最远索引
        var jump = 0 // 步数
        for (i in 0 until nums.size) {
            // 更新下一次最远的索引
            nextIndex = Math.max(nextIndex, i + nums[i])
            if (i == currentIndex) { // 到达当前的最远索引了，必须得付出一步的代价，换取更大的跳跃范围
                jump++
                currentIndex = nextIndex
                if (nextIndex >= nums.size - 1) {
                    break
                }
            }
        }
        return jump
    }
}